Skip to content

feat(encryption): add isomorphic end-to-end encryption package - #6

Merged
3m1n3nc3 merged 1 commit into
mainfrom
feat/encryption-package
Aug 27, 2026
Merged

feat(encryption): add isomorphic end-to-end encryption package#6
3m1n3nc3 merged 1 commit into
mainfrom
feat/encryption-package

Conversation

@3m1n3nc3

Copy link
Copy Markdown
Member

Add @arkstack/encryption, a zero-dependency package built entirely on the
Web Crypto API so the same code runs in Node, Deno, Bun, browsers and
workers. A value encrypted on the server decrypts in the browser and the
other way around.

  • Cipher: AES-256-GCM with optional additional authenticated data
  • EncryptionKey: generate, hash from secret, PBKDF2 derive, HKDF expand,
    fingerprint, constant-time compare
  • Keys: key and identity generation plus constant-time comparison helpers
  • KeyPair: ECDH P-256 identities serialised as base64url SPKI/PKCS#8
  • SecureChannel: two-party E2E, shared key derived locally on both sides
  • SealedBox: anonymous encryption to a public key
  • NodeCipher: synchronous node:crypto cipher behind its own entry point,
    emitting byte-identical payloads, so browser bundles never pull in
    node:crypto

Encryption in @arkstack/common now wraps the package rather than owning
an implementation. encrypt() and decrypt() keep their synchronous
signatures, key derivation and payload format, so stored ciphertexts and
existing call sites are unaffected; the added key argument is optional.
Async, key-management and E2E methods are new surface.

APP_KEY is itself 32 base64url bytes, which the library would otherwise
treat as raw key material rather than a passphrase, so the wrapper routes
through NodeCipher.fromSecret() to keep hashing it with SHA-256.

encryption-compat.test.ts pins the wrapper against the previous
implementation, reproduced verbatim from git history, in both directions.

Add @arkstack/encryption, a zero-dependency package built entirely on the
Web Crypto API so the same code runs in Node, Deno, Bun, browsers and
workers. A value encrypted on the server decrypts in the browser and the
other way around.

- Cipher: AES-256-GCM with optional additional authenticated data
- EncryptionKey: generate, hash from secret, PBKDF2 derive, HKDF expand,
  fingerprint, constant-time compare
- Keys: key and identity generation plus constant-time comparison helpers
- KeyPair: ECDH P-256 identities serialised as base64url SPKI/PKCS#8
- SecureChannel: two-party E2E, shared key derived locally on both sides
- SealedBox: anonymous encryption to a public key
- NodeCipher: synchronous node:crypto cipher behind its own entry point,
  emitting byte-identical payloads, so browser bundles never pull in
  node:crypto

Encryption in @arkstack/common now wraps the package rather than owning
an implementation. encrypt() and decrypt() keep their synchronous
signatures, key derivation and payload format, so stored ciphertexts and
existing call sites are unaffected; the added key argument is optional.
Async, key-management and E2E methods are new surface.

APP_KEY is itself 32 base64url bytes, which the library would otherwise
treat as raw key material rather than a passphrase, so the wrapper routes
through NodeCipher.fromSecret() to keep hashing it with SHA-256.

encryption-compat.test.ts pins the wrapper against the previous
implementation, reproduced verbatim from git history, in both directions.
@3m1n3nc3
3m1n3nc3 merged commit 21f6ae6 into main Aug 27, 2026
4 checks passed
@3m1n3nc3
3m1n3nc3 deleted the feat/encryption-package branch August 27, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant